#include "viml/builtin_sys.h"
#include "viml/value.h"
#include <cstdlib>
#include <ctime>
#include <stdexcept>
#include <filesystem>
#include <thread>
#include <chrono>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/wait.h>
extern char** environ;  // 在Unix系统上声明environ变量
#endif

namespace fs = std::filesystem;

namespace viml {

// ========================================
// 环境变量操作实现
// ========================================

Value sys_getenv_builtin(const std::vector<Value>& args) {
    if (args.size() != 1) {
        throw std::runtime_error("sys_getenv() requires exactly 1 argument");
    }
    
    if (!args[0].is_string()) {
        throw std::runtime_error("sys_getenv() argument must be a string");
    }
    
    const char* value = std::getenv(args[0].as_string().c_str());
    if (value == nullptr) {
        return Value::nil();
    }
    
    return Value::string(value);
}

Value sys_setenv_builtin(const std::vector<Value>& args) {
    if (args.size() != 2) {
        throw std::runtime_error("sys_setenv() requires exactly 2 arguments");
    }
    
    if (!args[0].is_string() || !args[1].is_string()) {
        throw std::runtime_error("sys_setenv() arguments must be strings");
    }
    
    std::string name = args[0].as_string();
    std::string value = args[1].as_string();
    
    try {
#ifdef _WIN32
        if (_putenv_s(name.c_str(), value.c_str()) != 0) {
            return Value::boolean(false);
        }
#else
        if (setenv(name.c_str(), value.c_str(), 1) != 0) {
            return Value::boolean(false);
        }
#endif
        return Value::boolean(true);
    } catch (const std::exception&) {
        return Value::boolean(false);
    }
}

Value sys_environ_builtin(const std::vector<Value>& args) {
    if (args.size() != 0) {
        throw std::runtime_error("sys_environ() requires no arguments");
    }
    
    Value result = Value::dict();
    auto& dict = result.as_dict();
    
#ifdef _WIN32
    char* env = GetEnvironmentStrings();
    if (env != nullptr) {
        char* var = env;
        while (*var != '\0') {
            std::string entry(var);
            size_t pos = entry.find('=');
            if (pos != std::string::npos && pos > 0) {
                std::string key = entry.substr(0, pos);
                std::string value = entry.substr(pos + 1);
                dict[key] = Value::string(value);
            }
            var += entry.length() + 1;
        }
        FreeEnvironmentStrings(env);
    }
#else
    // Unix系统使用environ全局变量
    for (char** env = environ; *env != nullptr; ++env) {
        std::string entry(*env);
        size_t pos = entry.find('=');
        if (pos != std::string::npos) {
            std::string key = entry.substr(0, pos);
            std::string value = entry.substr(pos + 1);
            dict[key] = Value::string(value);
        }
    }
#endif
    
    return result;
}

// ========================================
// 进程执行实现
// ========================================

Value sys_execute_builtin(const std::vector<Value>& args) {
    if (args.size() != 1) {
        throw std::runtime_error("sys_execute() requires exactly 1 argument");
    }
    
    if (!args[0].is_string()) {
        throw std::runtime_error("sys_execute() argument must be a string");
    }
    
    std::string cmd = args[0].as_string();
    
    int exit_code = std::system(cmd.c_str());
    
#ifdef _WIN32
    return Value::make_number(exit_code);
#else
    // 在Unix系统上，需要提取实际的退出码
    if (WIFEXITED(exit_code)) {
        return Value::make_number(WEXITSTATUS(exit_code));
    } else {
        return Value::make_number(-1);
    }
#endif
}

Value sys_system_builtin(const std::vector<Value>& args) {
    // sys_system 和 sys_execute 功能相同
    return sys_execute_builtin(args);
}

// ========================================
// 系统信息查询实现
// ========================================

Value sys_platform_builtin(const std::vector<Value>& args) {
    if (args.size() != 0) {
        throw std::runtime_error("sys_platform() requires no arguments");
    }
    
#ifdef _WIN32
    return Value::string("windows");
#elif defined(__APPLE__)
    return Value::string("macos");
#elif defined(__linux__)
    return Value::string("linux");
#else
    return Value::string("unknown");
#endif
}

Value sys_cwd_builtin(const std::vector<Value>& args) {
    if (args.size() != 0) {
        throw std::runtime_error("sys_cwd() requires no arguments");
    }
    
    try {
        fs::path cwd = fs::current_path();
        return Value::string(cwd.string());
    } catch (const std::exception& e) {
        throw std::runtime_error("sys_cwd() failed: " + std::string(e.what()));
    }
}

Value sys_chdir_builtin(const std::vector<Value>& args) {
    if (args.size() != 1) {
        throw std::runtime_error("sys_chdir() requires exactly 1 argument");
    }
    
    if (!args[0].is_string()) {
        throw std::runtime_error("sys_chdir() argument must be a string");
    }
    
    try {
        fs::current_path(args[0].as_string());
        return Value::boolean(true);
    } catch (const std::exception&) {
        return Value::boolean(false);
    }
}

// ========================================
// 时间相关实现
// ========================================

Value sys_time_builtin(const std::vector<Value>& args) {
    if (args.size() != 0) {
        throw std::runtime_error("sys_time() requires no arguments");
    }
    
    std::time_t now = std::time(nullptr);
    return Value::make_number(static_cast<int64_t>(now));
}

Value sys_sleep_builtin(const std::vector<Value>& args) {
    if (args.size() != 1) {
        throw std::runtime_error("sys_sleep() requires exactly 1 argument");
    }
    
    if (!args[0].is_number() && !args[0].is_float()) {
        throw std::runtime_error("sys_sleep() argument must be a number");
    }
    
    double seconds;
    if (args[0].is_number()) {
        seconds = args[0].as_number();
    } else {
        seconds = args[0].as_float();
    }
    
    if (seconds < 0) {
        throw std::runtime_error("sys_sleep() argument must be non-negative");
    }
    
    auto duration = std::chrono::duration<double>(seconds);
    std::this_thread::sleep_for(duration);
    
    return Value::nil();
}

} // namespace viml
